#ifndef WORKFLOW_NET_GENERATOR_H
#define WORKFLOW_NET_GENERATOR_H

#include <node.h>

#include <QtCore/QList>
#include <QtCore/QPair>
#include <QtCore/QUuid>

namespace core
{
class IGraphicEditorItem;
}

namespace net
{
class IPlace;
}

namespace wfnet
{
class ColorSet;
class WfNet;
}

namespace swp
{
class SimGraphicData;

class WorkflowNetGenerator
{
public:
    static WorkflowNetGenerator* getInstance();
    static void destroy();

    wfnet::WfNet* generate(SimGraphicData* data);
    void destroyNet(wfnet::WfNet* net);

private:
    WorkflowNetGenerator();
    ~WorkflowNetGenerator();

    void traversing(core::IGraphicEditorItem* startPoint,
        core::IGraphicEditorItem* endPoint, SimGraphicData *data,
        wfnet::WfNet* net);

    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToNetPart(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing, wfnet::WfNet* net, SimGraphicData* data,
        wfnet::ColorSet* tokens, int& splitCounter, int& joinCounter,
        int& decisionCounter, int& mergeCounter);

    void connectNetPart(const core::IGraphicEditorItem* item, core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);

    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToActivity(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, SimGraphicData* data, wfnet::ColorSet* tokens);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToDecision(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing, wfnet::WfNet* net,
        wfnet::ColorSet* tokens, int& decisionCounter);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToJoin(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, wfnet::ColorSet* tokens, int& joinCounter);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToSplit(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, wfnet::ColorSet* tokens, int& splitCounter);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToMerge(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, wfnet::ColorSet* tokens, int& mergeCounter);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToStartPoint(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, wfnet::ColorSet* tokens);
    QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > transformToEndPoint(
        const core::IGraphicEditorItem* item, const QSet<core::Node* >& incoming, const QSet<core::Node* >& outgoing,
        wfnet::WfNet* net, SimGraphicData* data, wfnet::ColorSet* tokens);

    void connectActivity(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectDecision(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectJoin(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectSplit(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectMerge(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectStartPoint(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
    void connectEndPoint(core::Node* current, const QSet<core::Node* >& incoming, wfnet::WfNet* net, const QHash<core::Node*, QPair<QHash<core::Node*, QUuid>, QHash<core::Node*, QUuid> > >& connections);
};

} // namespace swp

#endif
